﻿/******************************************************************************************
*                                                                                         *    
*                              Developed by Bruno Pires                                   *
*                                                                                         *
*                             email: bruno@blastersystems.com                             *
*                               web: www.blastersystems.com                               *
*                              blog: www.blastersystems.com/blog                          *
*                           twitter: @brunoacpires                                        *
*                                                                                         *
*             Software available under GNU LGPL v3 License without any guarantee          *
*                                                                                         *    
* *****************************************************************************************/ 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenNI;
using System.Drawing;
using System.Windows.Threading;
using System.Windows.Media.Imaging;
using Pap.Service.ImageDepth;
using Pap.Service.ImageIR;
using Pap.Service.ImageSkl;
using Pap.Service.ImageVGA;
using Pap.Service.ImageRecorder;
using Pap.ExtensionHelper;

namespace Pap.Service
{
    public class PapKinect
    {
        public enum KinectServiceType
        {
            VGA,
            IR,
            Depth,
            Skl
        }

        private KinectServiceType ServiceType;
        public event EventHandler KinectDataUpdated;
        public event EventHandler GetNewPlayerFrame;

        private Context ctx;
        private DepthGenerator depthGenerator;
        private IRGenerator irGenerator;
        private ImageGenerator vgaGenerator;

        private PapDepth serviceDepth;
        private PapIR serviceIR;
        private PapVGA serviceVGA;
        private PapSkeleton serviceSkl;
        private PapRecorder serviceRecorder;

        private Bitmap depthBitmap;
        private WriteableBitmap vgaBitmap;
        private WriteableBitmap irBitmap;
        private ScriptNode scriptNode;

        public PapKinect(KinectServiceType type)
        {
            try
            {
                switch (type)
                {
                    case KinectServiceType.VGA:
                        ctx = Context.CreateFromXmlFile(StaticData.PapConfigRGB, out scriptNode);
                        break;
                    case KinectServiceType.IR:
                        ctx = Context.CreateFromXmlFile(StaticData.PapConfigIR, out scriptNode);
                        break;
                    case KinectServiceType.Depth:
                        ctx = Context.CreateFromXmlFile(StaticData.PapConfigDepth, out scriptNode);
                        break;
                    case KinectServiceType.Skl:
                        ctx = Context.CreateFromXmlFile(StaticData.PapConfigDepth, out scriptNode);
                        break;
                }

                var dispatcherTimer = new DispatcherTimer();
                dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
                dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 5);
                dispatcherTimer.Start();
            }
            catch (Exception ex)
            {

                throw new Exception(ex.Message);
            }
        }

        public void ProcessDepth()
        {
            depthGenerator = ctx.FindExistingNode(NodeType.Depth) as DepthGenerator;
            serviceDepth = new PapDepth();
            depthBitmap = serviceDepth.StartDataProcessing(ctx, depthGenerator);
        }

        public void ProcessInfraRed()
        {
            irGenerator = ctx.FindExistingNode(NodeType.IR) as IRGenerator;

            serviceIR = new PapIR();
            irBitmap = serviceIR.StartDataProcessing(ctx, irGenerator);
        }

        public void ProcessVGA()
        {
            vgaGenerator = ctx.FindExistingNode(NodeType.Image) as ImageGenerator;
            serviceVGA = new PapVGA();
            vgaBitmap = serviceVGA.StartDataProcessing(ctx, vgaGenerator);
        }

        public void ProcessSkeleton()
        {
            ProcessDepth();
            serviceSkl = new PapSkeleton();
            serviceSkl.StartDataProcessing(ctx);
        }

        public BitmapImage GetDepthFrame()
        {
            if (serviceDepth != null)
            {
                return serviceDepth.UpdateDepth(depthGenerator, depthBitmap);
            }

            return null;
        }

        public WriteableBitmap GetInfraRedFrame()
        {
            if (serviceIR != null)
            {
                return serviceIR.UpdateIr(irGenerator, irBitmap);
            }

            return null;
        }

        public WriteableBitmap GetVGAFrame()
        {
            if (serviceVGA != null)
            {
                return serviceVGA.UpdateRgb(vgaGenerator, vgaBitmap);
            }

            return null;
        }

        public BitmapImage GetSkeletonFrame()
        {
            if (serviceSkl != null && serviceDepth != null)
            {
                return serviceSkl.DrawSkeletonImageBMP(depthBitmap, depthGenerator).getBitmapImage();
            }

            return null;
        }

        public void StopServices()
        {
            ctx.StopGeneratingAll();
            ctx.Release();
            ctx = null;
        }

        void dispatcherTimer_Tick(object sender, EventArgs e)
        {
            try
            {
                if (ctx!=null)
                {
                    ctx.WaitNoneUpdateAll();
                    
                    if (KinectDataUpdated!=null)
                    {
                        KinectDataUpdated(this, e);

                        if (serviceRecorder != null)
                        {
                            serviceRecorder.SaveData(depthGenerator);
                        }
                    }
                }

                
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void StartDepthRecording(string recordDestination)
        {
            ProcessDepth();
            serviceRecorder = new PapRecorder();
            serviceDepth.StartDataProcessing(ctx, depthGenerator);
            serviceRecorder.Record(ctx, depthGenerator, recordDestination);
        }

        public void PlayRecording(string filePath)
        {
            serviceRecorder = new PapRecorder();
            serviceRecorder.LoadRecording(filePath);
            serviceRecorder.GetNewFrame += new EventHandler(serviceRecorder_GetNewFrame);
        }

        public BitmapImage GetPlayerDepthFrame()
        {
            if (serviceRecorder == null)
            {
                return null;
            }
            return serviceRecorder.UpdateRecordingDepth(depthBitmap);
        }

        public void StopRecording()
        {
            if (serviceRecorder!=null)
            {
                serviceRecorder.StopRecorder();
                serviceRecorder = null;
            }
        }

        public void StopPlayer()
        {
            serviceRecorder.StopPlayer();
        }

        void serviceRecorder_GetNewFrame(object sender, EventArgs e)
        {
            if (GetNewPlayerFrame!=null)
            {
                GetNewPlayerFrame(sender, e);   
            }
        }
    }
}
